﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace mirror
{
    class cRenderer : Singleton<cRenderer>
    {
        RenderTarget2D resolveTarget;
        RenderTarget2D renderTarget1; 
        RenderTarget2D renderTarget2;
        Model shipModel;
        
        public List<cBaseRenderEffect> mEffects = new List<cBaseRenderEffect>();

        List<sRenderMe> mRenderUs;

        struct sRenderMe
        {
            public Model mModel;
            public Matrix mTransform;
            // public Texture2D[] mTextures;
            public sRenderMe(Model model, Matrix transform)//, Texture2D[] textures = null)
            {
                mModel = model; mTransform = transform; //mTextures = textures;
            }
            
        }

        public cRenderer()
        {
            mRenderUs = new List<sRenderMe>(128);
        }

        public void Unload()
        {
            resolveTarget.Dispose();
            renderTarget1.Dispose();
            renderTarget2.Dispose();
        }

        public void Initialise(mirror.Game1 zGame)
        {
            PrepareRenderTargets(zGame);
            shipModel = cModelManager.Instance.LoadModel("models/ship1");
            AddBloomEffect(zGame);
           // AddSimpleBloomEffect(zGame);
           // AddDesaturateEffect(zGame);
        }

        public void PrepareRenderTargets(mirror.Game1 zGame)
        {
            // Look up the resolution and format of our main backbuffer.
            PresentationParameters pp = zGame.GraphicsDevice.PresentationParameters;

            int width = pp.BackBufferWidth;
            int height = pp.BackBufferHeight;

            SurfaceFormat format = pp.BackBufferFormat;

            // Create a texture for reading back the backbuffer contents.
            resolveTarget = new RenderTarget2D(zGame.GraphicsDevice, width, height, false, format, DepthFormat.Depth24);

            // Create two rendertargets for the bloom processing. These are half the
            // size of the backbuffer, in order to minimize fillrate costs. Reducing
            // the resolution in this way doesn't hurt quality, because we are going
            // to be blurring the bloom images in any case.
            width /= 2;
            height /= 2;

            renderTarget1 = new RenderTarget2D(zGame.GraphicsDevice, width, height, false, format, DepthFormat.Depth24);
            renderTarget2 = new RenderTarget2D(zGame.GraphicsDevice, width, height, false, format, DepthFormat.Depth24);
        }

        public void AddSimpleBloomEffect(mirror.Game1 zGame)
        {
            cSimpleBloomEffect simpleBloom = new cSimpleBloomEffect(zGame);
            simpleBloom.Initialise(zGame);
            mEffects.Add(simpleBloom);
        }

        public void AddBloomEffect(mirror.Game1 zGame)
        {
            cBloomEffect bloomEffect = new cBloomEffect(zGame);
            bloomEffect.Initialise(zGame);
            mEffects.Add(bloomEffect);
        }

        public void AddDesaturateEffect(mirror.Game1 zGame)
        {
            cDesaturateEffect desaturateEffect = new cDesaturateEffect(zGame);
            desaturateEffect.Initialise(zGame);
            mEffects.Add(desaturateEffect);
        }

        public void Draw(GameTime gameTime)
        {
            //Render();
            // now do full screen effect:
            mEffects[0].Draw(gameTime, resolveTarget, renderTarget1, renderTarget2);
        }

        public void PreRender(Model model, Matrix transform)//, Texture2D[] textures)
        {
            mRenderUs.Add(new sRenderMe(model, transform));//, textures));
        }

        public void Render(Camera camera)
        {
            foreach (sRenderMe renderMe in mRenderUs)
            {
                Model model = renderMe.mModel;
                Matrix[] modelTransforms = new Matrix[model.Bones.Count];
                model.CopyAbsoluteBoneTransformsTo(modelTransforms);

                foreach (ModelMesh mesh in model.Meshes)
                {
                    foreach (BasicEffect effect in mesh.Effects)
                    {
                        effect.EnableDefaultLighting();

                        effect.View = camera.ViewMatrix;
                        effect.Projection = camera.ProjectionMatrix;
                        effect.World = modelTransforms[mesh.ParentBone.Index] * renderMe.mTransform;
                    }
                    mesh.Draw();
                }
            }
        }

        public void PostRender()
        {
            mRenderUs.Clear();
        }

        public void DrawScene(GraphicsDevice graphics, Effect effect)
        {
            graphics.DepthStencilState.DepthBufferEnable = true;
            graphics.RasterizerState.CullMode = CullMode.CullCounterClockwiseFace;
            graphics.BlendState = BlendState.Opaque;

            effect.Parameters["World"].SetValue(Matrix.Identity);
            effect.Parameters["View"].SetValue(Camera.Instance.ViewMatrix);
            effect.Parameters["Projection"].SetValue(Camera.Instance.ProjectionMatrix);
            // renderGBufferEffect.Parameters["Texture"].SetValue(sthhipColor);

            effect.CurrentTechnique.Passes[0].Apply();


            foreach (sRenderMe renderMe in mRenderUs)
            {
                Model model = renderMe.mModel;
                Matrix[] modelTransforms = new Matrix[model.Bones.Count];
                model.CopyAbsoluteBoneTransformsTo(modelTransforms);

                foreach (ModelMesh mesh in model.Meshes)
                {

                    effect.Parameters["World"].SetValue(modelTransforms[mesh.ParentBone.Index] * renderMe.mTransform);

                    foreach (ModelMeshPart meshPart in mesh.MeshParts)
                    {
                        graphics.SetVertexBuffer(meshPart.VertexBuffer);
                        graphics.Indices = meshPart.IndexBuffer;
                        graphics.DrawIndexedPrimitives(PrimitiveType.TriangleList,
                                                                                                0, 0,
                                                                                                meshPart.NumVertices,
                                                                                                meshPart.StartIndex,
                                                                                                meshPart.PrimitiveCount);
                    }

                }
            }


          
        }
    }
}
